package com.yc.cloud.openai.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.yc.cloud.basic.config.PathUtils;
import com.yc.cloud.basic.exception.Asserts;
import com.yc.cloud.basic.utils.MyFileConvertUtils;
import com.yc.cloud.basic.utils.MyFileUtils;
import com.yc.cloud.openai.constants.OpenAiConstants;
import com.yc.cloud.openai.dto.NLPResultDTO;
import com.yc.cloud.openai.dto.NlpChunkResultDto;
import com.yc.cloud.openai.dto.resp.XFNLPApiResp;
import com.yc.cloud.openai.request.NLPParam;
import com.yc.cloud.openai.service.NLPService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.codec.binary.Base64;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import reactor.core.publisher.Flux;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

/**
 * 科大讯飞API方式请求aiui
 */
@Service("XFNLPApiServiceImpl")
@Slf4j
public class XFNLPApiServiceImpl implements NLPService {

    private static final String URL = "http://openapi.xfyun.cn/v2/aiui";

    //191****3095 这个账号下的内容
    private static final String APPID = "a7f41698";
    private static final String API_KEY = "9380c45a5f97d55093401dcb844d008d";
    //    private static final String APPID = "21758286";
//    private static final String API_KEY = "da70f255695503cb2e6d891de8c5af01";
    private static final String DATA_TYPE = "audio";
    private static final String SCENE = "main_box";
    private static final String SAMPLE_RATE = "16000";
    private static final String AUTH_ID = "2894c985bf8b1111c6728db79d3479ae";
    private static final String AUE = "raw";

    private static final String SUCCESS_CODE = "0";

    private final String SUB_IAT = "iat";
    private final String SUB_NLP = "nlp";
    private final String SUB_TTS = "tts";

    @SneakyThrows
    @Override
    public NLPResultDTO getNLPResult(NLPParam param) {
        val nlpStartTime = System.currentTimeMillis();
        val header = buildHeader(param);
        val data = FileUtil.readBytes(param.getContent());
        String result = httpPost(header, data);
        //log.debug("XFNLPApiServiceImpl getNLPResult---->{}", result);
        if (StrUtil.isEmpty(result)) {
            return null;
        }
        val xfnlpApiResp = JSONUtil.toBean(result, XFNLPApiResp.class);
        //响应失败
        if (!SUCCESS_CODE.equals(xfnlpApiResp.getCode())) {
            log.error("XFNLPApiServiceImpl ERROR--->{}", xfnlpApiResp.getDesc());
            Asserts.fail(xfnlpApiResp.getDesc());
        }
        val nlpDtpResult = new NLPResultDTO();
        val dataDTOList = xfnlpApiResp.getData();
        dataDTOList.forEach(dataDTO -> {
            val sub = dataDTO.getSub();
            if (SUB_IAT.equals(sub)) {
                log.info("XF IAT 语音听写结果---->{}", dataDTO.getText());
                nlpDtpResult.setIatResult(dataDTO.getText());
            } else if (SUB_NLP.equals(sub)) {
                if (dataDTO.getIntent() != null && dataDTO.getIntent().getAnswer() != null) {
                    nlpDtpResult.setResult(dataDTO.getIntent().getAnswer().getText());
                    log.info("XF NLP 语音NLP结果---->{}", dataDTO.getIntent().getAnswer().getText());
                }
            } else if (SUB_TTS.equals(sub)) {
                nlpDtpResult.setTtsResult(dataDTO.getContent());
                if (StrUtil.isNotEmpty(dataDTO.getContent())) {
                    //当前数据为pcm格式,使用ffmpeg将pcm数据转成wav,h5方便显示
                    val pcmPath = Paths.get(PathUtils.getTempBasePath(), System.currentTimeMillis() + "-xf-nlp.pcm").toString();
                    MyFileUtils.decodeAndSaveFile(dataDTO.getContent(), pcmPath);
                    val wavPath = pcmPath.replace(".pcm", ".wav");
                    MyFileConvertUtils.pcm2wav(pcmPath, wavPath);
                    val wavBase64Data = MyFileUtils.convertToBase64(FileUtil.file(wavPath));
                    nlpDtpResult.setTtsResult(wavBase64Data);
                }
                //log.info("XF TTS 语音听写结果---->{}", dataDTO.getContent());
            }
        });
        val nlpEndTime = System.currentTimeMillis();
        nlpDtpResult.setCostTime(nlpEndTime - nlpStartTime);
        return nlpDtpResult;
    }

    @Override
    public Flux<String> getNLPResultByStream(NLPParam param) {
        return null;
    }

    @Override
    public Flux<ServerSentEvent<String>> getNLPResultByStream2(NLPParam param) {
        return null;
    }

    @Override
    public SseEmitter getNLPResultByStream3(NLPParam nlpParam) {
        return null;
    }

    private Map<String, String> buildHeader(NLPParam nlpParam) {
        String appKey = nlpParam.getAppKey();
        String appid = nlpParam.getAppid();
        if (StrUtil.isEmpty(appKey)) {
            appKey = API_KEY;
        }
        if (StrUtil.isEmpty(appid)) {
            appid = APPID;
        }
        String curTime = System.currentTimeMillis() / 1000L + "";
        // 使用 HashMap 构建参数
        Map<String, String> params = new HashMap<>();
        params.put("aue", AUE);
        params.put("sample_rate", SAMPLE_RATE);
        params.put("auth_id", AUTH_ID);
        params.put("data_type", DATA_TYPE);
        params.put("scene", SCENE);
//        var vcn = "x2_xiaojuan";
        if (OpenAiConstants.GENDER_MAN.equals(nlpParam.getGender())) {
            params.put("vcn", "x_qige");
        } else {
            params.put("vcn", "x2_xiaojuan");
        }
        String param = JSONUtil.toJsonStr(params);
        //String param = "{\"aue\":\"" + AUE + "\",\"sample_rate\":\"" + SAMPLE_RATE + "\",\"auth_id\":\"" + AUTH_ID + "\",\"data_type\":\"" + DATA_TYPE + "\",\"scene\":\"" + SCENE + "\",\"vcn\":\"" + vcn + "\"}";
//        String param = "{\"aue\":\"" + AUE + "\",\"result_level\":\"" + RESULT_LEVEL + "\",\"sample_rate\":\"" +
//                SAMPLE_RATE + "\",\"auth_id\":\"" + AUTH_ID + "\",\"data_type\":\"" + DATA_TYPE +
//                "\",\"scene\":\"" + SCENE + "\"}";
        //使用个性化参数时参数格式如下：
        //String param = "{\"aue\":\""+AUE+"\",\"sample_rate\":\""+SAMPLE_RATE+"\",\"auth_id\":\""+AUTH_ID+"\",\"data_type\":\""+DATA_TYPE+"\",\"scene\":\""+SCENE+"\",\"pers_param\":\""+PERS_PARAM+"\"}";
        String paramBase64 = new String(Base64.encodeBase64(param.getBytes(StandardCharsets.UTF_8)));
        String checkSum = org.apache.commons.codec.digest.DigestUtils.md5Hex(appKey + curTime + paramBase64);

        Map<String, String> header = new HashMap<>();
        header.put("X-Param", paramBase64);
        header.put("X-CurTime", curTime);
        header.put("X-CheckSum", checkSum);
        header.put("X-Appid", appid);
        return header;
    }


    private String httpPost(Map<String, String> header, byte[] body) {
        StringBuilder result = new StringBuilder();
        BufferedReader in = null;
        OutputStream out = null;
        try {
            java.net.URL realUrl = new URL(URL);
            HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection();
            for (String key : header.keySet()) {
                connection.setRequestProperty(key, header.get(key));
            }
            connection.setDoOutput(true);
            connection.setDoInput(true);

            //connection.setConnectTimeout(20000);
            //connection.setReadTimeout(20000);
            try {
                out = connection.getOutputStream();
                out.write(body);
                out.flush();
            } catch (Exception e) {
                e.printStackTrace();
            }

            try {
                in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String line;
                while ((line = in.readLine()) != null) {
                    result.append(line);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result.toString();
    }


}
